<?php

namespace App\Http\Controllers\H5;

use App\Common\SDK\Domain\FenZhangTong;
use App\Common\Utils\Helper;
use App\Http\Controllers\Controller;
use App\Models\Agent;
use App\Models\AgentPromoted;
use App\Models\AgentWebsiteLetter;
use App\Models\AgentXiamenBankAccount;
use App\Models\DailyReportStatistics;
use App\Models\FinanceSupplier;
use App\Models\IndicatorsDailySummary;
use App\Models\IndicatorsMonthlySummary;
use App\Models\SummaryBase;
use App\Services\AgentRewardRuleSettings;
use App\Services\Banner;
use App\Services\CacheLockKeyConst;
use App\Services\Captcha;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Http\Request;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Log;

class AgentController extends Controller
{
    public function register(Request $request)
    {
        if (!Captcha::verificationSmsCaptcha($request)) {
            $this->response->errorBadRequest('短信验证码错误或者已过期');
        }

        validator($request->all(), [
            'phone' => 'unique:agents',
            'name' => 'unique:agents'
        ], [
            'phone.unique' => '该手机号已注册',
            'name.unique' => '该名称已注册',
        ])->validate();

        try {
            // 解决 firstOrCreate 并发问题, 先创建
            /** @var DailyReportStatistics $dailyReportStatistics */
            $dailyReportStatistics = CacheLockKeyConst::dailyReportStatistics(Carbon::today());

            DB::beginTransaction();

            // 根据邀请码查询到邀请人
            $inviter = null;
            if ($invitationCode = $request->get('invitation_code')) {
                $inviter = Agent::query()
                    ->where('invitation_code', strtoupper($invitationCode))
                    ->first();
                if ($inviter) {
                    $inviter->increment('number_of_direct_inviter');
                    if ($inviter['direct_inviter']) {
                        Agent::query()->find($inviter['direct_inviter'])->increment('number_of_indirect_inviter');
                    }
                }
            }

            // 间接邀请人
            // 邀请人 人数 + 1
            $agent = Agent::query()->create(tap(
                $request->only(['name', 'password', 'phone']),
                function (&$values) use ($inviter) {
                    $values['password'] = Hash::make($values['password']);
                    $values['invitation_code'] = Agent::generateInvitationCode();
                    if ($inviter) {
                        $parentPathId = array_filter(explode('-', $inviter['parent_path_id'] ?? ''));
                        $parentPathId[] = $inviter['id'];
                        $values['parent_path_id'] = implode('-', $parentPathId);
                        $values['direct_inviter'] = $inviter['id'];
                        $values['indirect_inviter'] = $inviter['direct_inviter'];
                        $values['affiliated_partner'] = $inviter['affiliated_partner'] ?? 0; // 所属合伙人
                    }
                }
            ));

            // 累计新增代理总数
            $dailyReportStatistics->incrementOrDecrementAgent();

            DB::commit();
        } catch (\Exception $e) {
            DB::rollBack();
            $this->response->errorBadRequest($e->getMessage());
        }

        return $this->response->created(null, $agent);
    }

    public function info(Request $request)
    {
        $agents = Agent::query()
            ->with(['directInviter', 'indirectInviter', 'wechat', 'partnerIdentity',
                'indicatorsDailySummary' => fn(HasMany $hasMany) => $hasMany
                    ->whereIn('type', [SummaryBase::TYPE_AGENT, SummaryBase::TYPE_TEAM])
                    ->where('day', Carbon::now()->format('Y-m-d')),
                'indicatorsMonthlySummary' => fn(HasMany $hasMany) => $hasMany
                    ->whereIn('type', [SummaryBase::TYPE_AGENT, SummaryBase::TYPE_TEAM])
                    ->where('month', Carbon::now()->format('Ym')),
            ])
            ->withCount(['websiteLetter as unread_station_letter' => function (Builder $builder) {
                $builder->where('status', AgentWebsiteLetter::STATUS_UNREAD);
            }])
            ->find($this->user->getKey())
            ->toArray();
        return tap($agents, function (&$agent) {
            // 代理商 团队 统计
            $agent['agent_indicators_daily_summary'] = null;
            $agent['agent_indicators_monthly_summary'] = null;
            $agent['team_indicators_daily_summary'] = null;
            $agent['team_indicators_monthly_summary'] = null;
            foreach ($agent['indicators_daily_summary'] as $item) {
                if ($item['type'] === SummaryBase::TYPE_AGENT) {
                    $agent['agent_indicators_daily_summary'] = $item;
                } elseif ($item['type'] === SummaryBase::TYPE_TEAM) {
                    $agent['team_indicators_daily_summary'] = $item;
                }
            }
            foreach ($agent['indicators_monthly_summary'] as $item) {
                if ($item['type'] === SummaryBase::TYPE_AGENT) {
                    $agent['agent_indicators_monthly_summary'] = $item;
                } elseif ($item['type'] === SummaryBase::TYPE_TEAM) {
                    $agent['team_indicators_monthly_summary'] = $item;
                }
            }
            $agent['total_balance'] = $agent['balance'] + $agent['unextractable_balance']; // 总余额
            $agent['system'] = [
                'banner' => Banner::getBannerList(), // 首页 Banner
                'recharge_reward' => AgentRewardRuleSettings::getSettingsByCache(\App\Models\AgentRewardRuleSettings::TYPE_RECHARGE_BONUS)
            ];
            // 显示团队大咖
            $agent['team_leader'] = '省到家团队';
            // 1. 直接/间接 邀请 是否有大咖
            $directInviterIsStrongMan = $agent['direct_inviter'] && ($agent['direct_inviter']['level'] === Agent::LEVEL_STRONGMAN);
            $indirectInviterIsStrongMan = $agent['indirect_inviter'] && ($agent['indirect_inviter']['level'] === Agent::LEVEL_STRONGMAN);
            if ($directInviterIsStrongMan || $indirectInviterIsStrongMan) {
                if ($directInviterIsStrongMan) {
                    $agent['team_leader'] = $agent['direct_inviter']['name'] . '团队';
                } elseif ($indirectInviterIsStrongMan) {
                    $agent['team_leader'] = $agent['indirect_inviter']['name'] . '团队';
                }
            } else {
                // 往上寻找合伙人
                $parentIds = explode('-', $agent['parent_path_id']);
                if (!empty($parentIds)) {
                    $parents = arrayCombineByKey(
                        Agent::query()
                            ->withoutGlobalScope('created_at')
                            ->whereHas('partnerIdentity')
                            ->whereIn('id', $parentIds)
                            ->get()
                            ->toArray(),
                        'id'
                    );
                    foreach (array_reverse($parentIds) as $parentId) {
                        if (isset($parents[$parentId])) {
                            $agent['team_leader'] = $parents[$parentId]['name'] . '团队';
                            break;
                        }
                    }
                }
            }

            // 缓存 tags namespace (前端依靠这个来判断缓存是否过期
            $agent['cache_tags_namespace'] = [
                'commodity_activity_list_cache' => Cache::tags('commodity_activity_list_cache')->getTags()->getNamespace(), // 活动缓存
            ];
        });
    }

    public function update(Request $request)
    {
        validator($request->all(), [
            'name' => 'unique:agents'
        ], [
            'name.unique' => '该名称已注册',
        ])->validate();

        $this->user()->update(tap(
            array_filter(
                $request->only([
                    'real_name', 'name', 'wechat_number', 'address', 'province', 'city', 'area', 'birthday', 'gender'
                ])
            ),
            function (&$values) {
                $values['is_agree_user_agreement'] = true;
            }
        ));

        return $this->response->created(null);
    }

    public function promotedList(Request $request)
    {
        return $this->response->array(
            Helper::dealWithNotCompatibleSimplePaginate(
                AgentPromoted::query()
                    ->where('agent_id', $this->user['id'])
                    ->where('status', AgentPromoted::STATUS_PROMOTED)
                    ->simplePaginate()
            )
        );
    }

    public function infoBySearch(Request $request)
    {
        return $this->response->array(
            Agent::query()
                ->with(['partnerIdentity'])
                ->when($request->get('phone', ''), function (Builder $builder, $phone) {
                    $builder->where('phone', 'like', "%$phone%");
                })
                ->firstOrFail()
                ->toArray()
        );
    }

    /**
     * 业绩明细
     * @param Request $request
     * @return mixed
     */
    public function performanceDetails(Request $request)
    {
        /** @var Builder $model */
        $model = [
            SummaryBase::TIME_DIMENSION_DAILY => IndicatorsDailySummary::query()->orderByDesc('day'),
            SummaryBase::TIME_DIMENSION_MONTHLY => IndicatorsMonthlySummary::query()->orderByDesc('month'),
        ][$request->get('time_dimension', SummaryBase::TIME_DIMENSION_DAILY)];

        return $this->response->array(
            Helper::dealWithNotCompatibleSimplePaginate(
                $model
                    ->where('agent_id', \Auth::id())
                    ->where('type', $request->get('type', SummaryBase::TYPE_AGENT))
                    ->simplePaginate()
            )
        );
    }

    /**
     * 重置手机号
     */
    public function resetPhone(Request $request)
    {
        // 重设手机号时,获取当前用户手机号,不能还是老的手机号
        if (($this->user['phone'] ?? '') === ($phone = $request->get('phone'))) {
            abort(400, '请不要使用当前账户的手机号');
        }
        if (!Captcha::verificationSmsCaptcha($request)) {
            $this->response->errorBadRequest('短信验证码错误或者已过期');
        }

        \Cache::lock('reset_phone_' . $phone, 3)->block(3, function () use ($phone) {
            // 是否已在别的账号上使用
            if (Agent::query()->where('phone', $phone)->exists()) {
                abort(400, '号码已存在,修改失败');
            }

            \Log::info(sprintf('修改手机号; 原来: %s 现在: %s', $this->user['phone'] ?? '', $phone));
            $this->user->update(['phone' => $phone]);
        });

        return $this->response->noContent();
    }

    /**
     * 厦门银行个人用户注册
     */
    public function xiamenBankRegister(Request $request)
    {
        $reqData = validator($request->all(), [
            'name' => 'required',
            'id_type' => 'required|in:' . implode(',', [FinanceSupplier::ID_TYPE_MAINLAND, FinanceSupplier::ID_TYPE_HONG_KONG_AND_MACAU, FinanceSupplier::ID_TYPE_TAIWAN]),
            'id_no' => 'required',

            'legal_expire_date' => 'required_if:id_type,A|date',
            'legal_auth_date' => 'required_if:id_type,A|date',
            'occupation' => 'required_if:id_type,A|in:0001,0002,0003,0004,0005,0006,0007,0008,0009,0010',
            'address' => 'required_if:id_type,A',
            'legal_address' => 'required_if:id_type,A',
            'issue_office' => 'required_if:id_type,A',

            'bank' => 'required|in:' . implode(',', array_keys(FinanceSupplier::GUO_JI_YIN_HANG_MAP)),
            'bank_card_no' => 'required',
            'phone' => ['required', 'regex:/^(?:\+?86)?1(?:3\d{3}|5[^4\D]\d{2}|8\d{3}|7(?:[235-8]\d{2}|4(?:0\d|1[0-2]|9\d))|9[0-35-9]\d{2}|66\d{2})\d{6}$/'],
        ], [
            'name.required' => '姓名为必填项',
            'id_type.required' => '证件类型不得为空',
            'id_type.in' => '证件类型不合法',
            'id_no.required' => '证件号码为必填项',
            'legal_expire_date.required_if' => '证件有效期为必填项',
            'legal_auth_date.required_if' => '证件起始日期为必填项',
            'occupation.required_if' => '职业为必填项',
            'occupation.in' => '职业不合法',
            'address.required_if' => '联系地址为必填项',
            'legal_address.required_if' => '证件地址为必填项',
            'issue_office.required_if' => '发证机关为必填项',
            'bank.required' => '银行为必选项',
            'bank.in' => '银行不合法',
            'bank_card_no.required' => '银行卡号为必填项',
            'phone.required' => '预留手机号为必填项',
            'phone.regex' => '预留手机号填写不正确',
        ])->validate();

        try {
            $alreadyExists = AgentXiamenBankAccount::query()->where(['agent_id' => \Auth::id(), 'status' => AgentXiamenBankAccount::STATUS_NORMAL])->first();
            if (!empty($alreadyExists)) {
                $this->response->errorBadRequest('已经注册过啦,不要重复注册');
            }

            DB::beginTransaction();

            $transId = substr(app('Barryvdh\Debugbar\LaravelDebugbar')->getRequestIdGenerator()->generate(), 1);
            $bankAccount = \Auth::user()->xiamenBankAccount()->create([
                'trans_id' => $transId, // 后面回调要用这个来查
                'name' => $reqData['name'],
                'id_type' => $reqData['id_type'],
                'id_no' => $reqData['id_no'],
                'legal_expire_date' => $reqData['legal_expire_date'] ?? '',
                'legal_auth_date' => $reqData['legal_auth_date'] ?? '',
                'address' => $reqData['address'] ?? '',
                'legal_address' => $reqData['legal_address'] ?? '',
                'issue_office' => $reqData['issue_office'] ?? '',
                'occupation' => $reqData['occupation'] ?? '',
            ]);
            $bankAccount->cards()->create([
                'agent_id' => \Auth::id(),
                'bank' => $reqData['bank'],
                'bank_card_no' => $reqData['bank_card_no'],
                'phone' => $reqData['phone'],
            ]);

            $fztReq = [
                'transId' => $transId, // 这里单独传 transId 后面回调要用这个来查

                'custName' => $reqData['name'],
                'idType' => $reqData['id_type'],
                'idNo' => $reqData['id_no'],

                'mobileNo' => $reqData['phone'],
                'openBank' => $reqData['bank'],
                'cardNo' => $reqData['bank_card_no'],

                'legalExpireDate' => $reqData['legal_expire_date'] ?? '',
                'legalAuthDate' => $reqData['legal_auth_date'] ?? '',
                'occupation' => $reqData['occupation'] ?? '',
                'address' => $reqData['address'] ?? '',
                'legalAddress' => $reqData['legal_address'] ?? '',
                'issueOffice' => $reqData['issue_office'] ?? '',

                'notifyUrl' => url('/api/h5/bank/account-notify'),
                'returnUrl' => url('h5/my'),
            ];
            $fztRes = \App\Common\SDK\Facade\FenZhangTong::individualCustomerRegistrationApplication(array_filter($fztReq, fn($item) => !empty($item)));
            $bankAccount->update(['plat_cust_no' => $fztRes['platCustNo'] ?? '', 'ret_url' => base64_encode($fztRes['retUrl'])]);

            DB::commit();

            return $this->response->array(['ret_url' => $fztRes['retUrl']]);
        } catch (\Exception $e) {
            DB::rollBack();

            Log::error(sprintf('处理分账通代理注册发生错误: %s (%s [%d])', $e->getMessage(), $e->getFile(), $e->getLine()));

            $this->response->errorBadRequest($e->getMessage());
        }
    }

    /**
     * 银行账号回调通知
     * @param Request $request
     */
    public function xiamenBankRegisterNotify(Request $request)
    {
        // 校验数据
        $reqData = $request->all();
        Arr::forget($reqData, 's');
        Log::info('接收分账通代理账号注册回调通知: ' . json_encode($reqData));
        if (!FenZhangTong::signVerify($reqData)) {
            Log::warning('接收分账通回调通知验签失败');
            $this->response->errorBadRequest('验签失败');
        }

        try {
            $agentBankAccount = AgentXiamenBankAccount::query()->where('trans_id', $reqData['oriTransId'])->firstOrFail();
            // 不是注册中状态
            if ($agentBankAccount['status'] !== AgentXiamenBankAccount::STATUS_REGISTERING) {
                return $this->response->noContent();
            }

            $agentBankAccount->update([
                'plat_cust_no' => $reqData['platCustNo'],
                'acct_no' => $reqData['acctNo'],
                'register_callback_snapshot' => $reqData,
                'check_stat' => $reqData['checkStat'],
                'remark' => $reqData['remark'],
                'status' => (int) $reqData['checkStat'] === 1 ? AgentXiamenBankAccount::STATUS_NORMAL : AgentXiamenBankAccount::STATUS_AUDIT_FAILURE
            ]);
        } catch (\Exception $e) {
            Log::error(sprintf('处理分账通代理注册回调发生错误: %s (%s [%d])', $e->getMessage(), $e->getFile(), $e->getLine()));

            $this->response->errorBadRequest($e->getMessage());
        }

        return $this->response->noContent();
    }
}
